package com.huahua.graduateschoolspringboot.server;

import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.huahua.graduateschoolspringboot.handler.IDeviceCommandHandler;
import com.huahua.graduateschoolspringboot.util.MessageUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * Socket拦截器，用于处理客户端的行为
 *
 * @author Gjing
 **/
@Slf4j
public class SocketHandler extends SimpleChannelInboundHandler<String> {
    public static final ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);


    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        log.info("新的客户端链接：" + ctx.channel().id().asShortText());
        clients.add(ctx.channel());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        clients.remove(ctx.channel());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.channel().close();
        clients.remove(ctx.channel());
    }

    /**
     * Is called for each message of type {@link I}.
     *
     * @param ctx the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler}
     *            belongs to
     * @param msg the message to handle
     * @throws Exception is thrown if an error occurred
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        try {
            log.info("完整消息 {}", msg);

            String header = StrUtil.subPre(msg, 8);
            //反转03FF2320 -> 2023ff03 两两反转
            //包头
            String header1 = StrUtil.sub(msg, 0, 4);
            String header2 = StrUtil.sub(msg, 4, 8);
            //包头再反转
            String subHeader1 = StrUtil.sub(header2, 2, 4);
            String subHeader2 = StrUtil.sub(header2, 0, 2);
            String subHeader3 = StrUtil.sub(header1, 2, 4);
            String subHeader4 = StrUtil.sub(header1, 0, 2);
            String finalHeader = subHeader1 + subHeader2 + subHeader3 + subHeader4;
            log.info("包头是 {}", finalHeader);
            //包标识
            String deviceTypeStr = StrUtil.sub(msg, 8, 10);
            Integer deviceType = NumberUtil.parseInt(deviceTypeStr);
            log.info("包标识str {}", deviceTypeStr);
            log.info("包标识 {}", deviceType);
            Integer commandBodyLength = HexUtil.hexToInt(StrUtil.sub(msg, 10, 14));
            // 包长度(L) =  指令长度+参数长度+校验和长度
            log.info("包长度 {}", commandBodyLength);
            Integer commandType = NumberUtil.parseInt(StrUtil.sub(msg, 14, 16));
            log.info("指令标识 {}", commandType);
            String command = StrUtil.sub(msg, 16, msg.length() - 4);
            log.info("指令 {}", command);
            //校验和
            String checksum = StrUtil.subSuf(msg, msg.length() - 4);
            log.info("校验和 {}", checksum);
            String jsonMsg = HexUtil.decodeHexStr(command);
            log.info("收到命令: " + jsonMsg);
            log.info("收到命令: " + msg);
            //这里处理硬件单片机数据(硬件存在共用)
            if (JSONUtil.isTypeJSON(jsonMsg)) {
                Object role = JSONUtil.parseObj(jsonMsg).get("Role");
                if (ObjUtil.isNotNull(role)) {
                    //路灯
                    MessageUtil.deviceMap.put(role.toString(), ctx.channel());
                }
            }
            //这里处理指定设备类型的数据
            for (IDeviceCommandHandler value : SpringUtil.getBeansOfType(IDeviceCommandHandler.class).values()) {
                ObjectMapper objectMapper = SpringUtil.getBean(ObjectMapper.class);
                if (value.support(deviceTypeStr)){
                    ObjectNode jsonNodes = objectMapper.readValue(jsonMsg, ObjectNode.class);
                    value.execute(jsonNodes);
                }
//{"help":1}
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}



